# coding=utf-8
# -*- coding: UTF-8 -*-
#
# This file is part of the kernelstudio package.
#
# (c) 2014-2023 zlin <admin@kernelstudio.com>
#
# For the full copyright and license information, please view the LICENSE file
# that was distributed with this source code.

import typing as t

import redis as rd


class RedisPersistence:
    host: t.Optional[str] = "127.0.0.1"
    port: t.Optional[int] = 6379
    username: t.Optional[str] = None
    password: t.Optional[str] = None
    namespace: t.Optional[str] = "ksai:"
    connection: t.Optional[rd.StrictRedis] | t.Optional[None] = None
    connected: t.Optional[bool] = False
    db: t.Optional[int] = 0

    def __init__(self):
        pass

    def connect(self,
                host: t.Optional[str] = "127.0.0.1",
                port: t.Optional[int] = 6379,
                db: t.Optional[int] = 0,
                namespace: t.Optional[str] = "ksai:",
                username: t.Optional[str] = None,
                password: t.Optional[str] = None,
                ):
        self.host = host
        self.port = port
        self.db = db
        self.namespace = namespace
        self.username = username
        self.password = password
        if self.connected is False or self.connection is None:
            self.connection = rd.StrictRedis(
                host=self.host,
                port=self.port,
                db=self.db,
                username=self.username,
                password=self.password
            )
        return self

    def disconnect(self):
        if self.connection is not None:
            self.connection.close()
            self.connection = None
            self.connected = False
        return self

    def put(self, key, value, expire=None):
        """
        写入键值对
        """
        self.connection.set(name=self.namespace + str(key), value=value, ex=expire)

    def get(self, key):
        """
        读取键值对内容
        """
        value = self.connection.get(name=self.namespace + key)
        return value.decode('utf-8') if value else value

    def left_put(self, name, value):
        self.connection.lpush(self.namespace + name, value)

    def left_pop(self, name):
        return self.connection.lpop(name=self.namespace + name)

    def right_put(self, name, value):
        self.connection.rpush(self.namespace + name, value)

    def right_pop(self, name):
        return self.connection.rpop(name=self.namespace + name)

    def map_put(self, name, key, value):
        """
        写入hash表
        """
        self.connection.hset(self.namespace + name, key, value)

    def map_get(self, name, key):
        """
        读取指定hash表的键值
        """
        value = self.connection.hget(self.namespace + name, key)
        return value.decode('utf-8') if value else value

    def map_values(self, name):
        """
        获取指定hash表所有的值
        """
        return self.connection.hgetall(self.namespace + name)

    def map_remove(self, name, key):
        """
        删除指定hash表的键值
        """
        self.connection.hdel(self.namespace + name, key)

    def map_keys(self, name):
        return self.connection.hkeys(self.namespace + name)

    def expire(self, name, expire=None):
        """
        设置过期时间
        """
        if expire:
            expire_in_seconds = expire
        else:
            expire_in_seconds = 0
        self.connection.expire(self.namespace + name, expire_in_seconds)

    def lock(
            self,
            name: str,
            timeout: t.Optional[float] = None,
            sleep: float = 0.1,
            blocking: bool = True,
            blocking_timeout: t.Optional[float] = None,
            lock_class: t.Union[None, t.Any] = None,
            thread_local: bool = True,
    ) -> t.Callable:
        return self.connection.lock(
            name=self.namespace + name,
            timeout=timeout,
            sleep=sleep,
            blocking=blocking,
            blocking_timeout=blocking_timeout,
            lock_class=lock_class,
            thread_local=thread_local,
        )
